#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "drv_i2c.h"
#include "main.h"
#include "gd32f20x_eval.h"
#include <rtthread.h>

/*!
	\brief      handle I2C1 event interrupt request
	\param[in]  none
	\param[out] none
	\retval     none
*/

I2CX_INTERRUPT_DATA i2c1_data;
I2CX_INTERRUPT_DATA i2c0_data;

rt_mutex_t i2c1_mutex = RT_NULL;
rt_mutex_t i2c0_mutex = RT_NULL;

rt_mq_t i2c1_mq;
rt_mq_t i2c0_mq;

uint32_t I2Cx[2] = {I2C0, I2C1};

/*!
	\brief      handle I2C0 event interrupt request
	\param[in]  none
	\param[out] none
	\retval     none
*/
void I2C0_EventIRQ_Handler(void)
{
	if (i2c0_data.master == I2C_MASTER_CH)
	{
		if (i2c0_data.send == 1)
		{
			if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SBSEND))
			{
				/* send slave address */
				i2c_master_addressing(I2C0, i2c0_data.addr, I2C_TRANSMITTER);
			}
			else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND))
			{
				/*clear ADDSEND bit */
				i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);
			}
			else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE))
			{
				if (i2c0_data.txcount > 0)
				{
					/* the master sends a data byte */
					i2c_data_transmit(I2C0, i2c0_data.txbuf[i2c0_data.txindex++]);
					i2c0_data.txcount--;
				}
				else
				{
					/* the master sends a stop condition to I2C bus */
					i2c_stop_on_bus(I2C0);
					i2c0_data.txdone = 1;
					// printf("i2c0 master tx done.\n");

					/* disable the I2C0 interrupt */
					// fixed slave can't receive 'stop'.
					//					i2c_interrupt_disable(I2C0, I2C_INT_ERR);
					//					i2c_interrupt_disable(I2C0, I2C_INT_EV);
					//					i2c_interrupt_disable(I2C0, I2C_INT_BUF);
				}
			}
		}
		else // i2c0_data.send == 0
		{
			if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SBSEND))
			{
				/* the master sends slave address */
				i2c_master_addressing(I2C0, i2c0_data.addr, I2C_RECEIVER);
			}
			else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND))
			{
				if ((1 == i2c0_data.rxcount) || (2 == i2c0_data.rxcount))
				{
					/* clear the ACKEN before the ADDSEND is cleared */
					i2c_ack_config(I2C0, I2C_ACK_DISABLE);
					/* clear the ADDSEND bit */
					i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);
				}
				else
				{
					/* clear the ADDSEND bit */
					i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);
				}
			}
			else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE))
			{
				if (i2c0_data.rxcount > 0)
				{
					if (3 == i2c0_data.rxcount)
					{
						/* wait until the second last data byte is received into the shift register */
						while (!i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_BTC))
							;
						/* send a NACK for the last data byte */
						i2c_ack_config(I2C0, I2C_ACK_DISABLE);
					}
					/* read a data byte from I2C_DATA*/
					i2c0_data.rxbuf[i2c0_data.rxindex++] = i2c_data_receive(I2C0);
					i2c0_data.rxcount--;
					if (0 == i2c0_data.rxcount)
					{
						i2c_stop_on_bus(I2C0);
						i2c0_data.rxdone = 1;
						// printf("i2c0 master rx done.\n");

						i2c_ack_config(I2C0, I2C_ACK_ENABLE);
						i2c_ackpos_config(I2C0, I2C_ACKPOS_CURRENT);
						i2c_interrupt_disable(I2C0, I2C_INT_ERR);
						i2c_interrupt_disable(I2C0, I2C_INT_EV);
						i2c_interrupt_disable(I2C0, I2C_INT_BUF);
					}
				}
			} // i2c_interrupt_flag_get
		}
	}
	else // i2c0_data.master == 0
	{
		// recv

		if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND))
		{
			/* clear the ADDSEND bit */
			i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);
		}
		else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE))
		{
			/* if reception data register is not empty ,I2C0 will read a data from I2C_DATA */
			i2c0_data.rxbuf[i2c0_data.rxindex++] = i2c_data_receive(I2C0);
			// printf("recv flag data: %02X\n", i2c1_data.rxbuf[i2c1_data.rxindex]);
		}
		else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_STPDET))
		{
			// printf("I2C0_INT_FLAG_STPDET.\n");

			if (i2c0_data.send == 0)
			{
				i2c0_data.rxdone = 1;
//				rt_kprintf("i2c0 slave rx done.\n");

				if(i2c0_data.rxcount <32){
						
					int result = rt_mq_send(i2c0_mq , (void *)i2c0_data.rxbuf , 128);
					if(result != RT_EOK)
					{
						if(result == -RT_EFULL)
						{
							rt_kprintf("I2C0_EventIRQ_Handler rt_mq_send ERR, rt_mq is Full! err_code = %d\n", result);
						}else{
							rt_kprintf("I2C0_EventIRQ_Handler rt_mq_send ERR, err_code = %d\n", result);
						}
					}
					
				}else{
					rt_kprintf("i2c0 slave rx data >32 bytes.\n");
				}
				i2c0_data.rxcount = 0;
				//memset((void *)i2c0_data.rxbuf, 0, 128);
				i2c0_data.rxindex = 0;
			}

			/* clear the STPDET bit */
			i2c_enable(I2C0);
		}

		// send

		if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND))
		{
			/* clear the ADDSEND bit */
			i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);
		}
		else if ((i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE)) && (!i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_AERR)))
		{
			/* send a data byte */
			i2c_data_transmit(I2C0, i2c0_data.txbuf[i2c0_data.txindex++]);

			if (i2c0_data.txcount == i2c0_data.txindex)
			{
				i2c0_data.txdone = 1;
				// i2c0_data.txindex = 0;
				// printf("i2c0 slave tx done.\n");
			}
		}
	}
}
/*!

	\brief      handle I2C0 error interrupt request
	\param[in]  none
	\param[out] none
	\retval     none
*/
void I2C0_ErrorIRQ_Handler(void)
{
	/* no acknowledge received */
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_AERR))
	{
		i2c0_data.status |= (1 << 0);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_AERR);
		printf("no acknowledge received\r\n");
	}

	/* SMBus alert */
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SMBALT))
	{
		i2c0_data.status |= (1 << 1);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_SMBALT);
		printf("SMBus alert\r\n");
	}

	/* bus timeout in SMBus mode */
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SMBTO))
	{
		i2c0_data.status |= (1 << 2);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_SMBTO);
		printf("bus timeout in SMBus mode\r\n");
	}

	/* over-run or under-run when SCL stretch is disabled */
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_OUERR))
	{
		i2c0_data.status |= (1 << 3);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_OUERR);
		printf("over-run or under-run when SCL stretch is disabled\r\n");
	}

	/* arbitration lost */
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_LOSTARB))
	{
		i2c0_data.status |= (1 << 4);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_LOSTARB);
		printf("arbitration lost\r\n");
	}

	/* bus error */
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_BERR))
	{
		i2c0_data.status |= (1 << 5);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_BERR);
		printf("bus error\r\n");
	}

	/* CRC value doesn't match */
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_PECERR))
	{
		i2c0_data.status |= (1 << 6);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_PECERR);
		printf("CRC value doesn't match\r\n");
	}

	// I2C_DATA is empty during transmitting interrupt flag
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE))
	{
		i2c0_data.status |= (1 << 7);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_TBE);
		printf("DATA is empty during transmitting\r\n");
	}

	// I2C_DATA is not Empty during receiving interrupt flag
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_RBNE))
	{
		i2c0_data.status |= (1 << 8);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_RBNE);
		printf("DATA is not Empty during receiving\r\n");
	}

	// stop condition detected in slave mode interrupt flag
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_STPDET))
	{
		i2c0_data.status |= (1 << 9);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_STPDET);
		printf("stop condition detected\r\n");
	}

	// header of 10-bit address is sent in master mode interrupt flag
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADD10SEND))
	{
		i2c0_data.status |= (1 << 10);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADD10SEND);
		printf("stop condition detected\r\n");
	}

	// byte transmission finishes
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_BTC))
	{
		i2c0_data.status |= (1 << 11);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_BTC);
		printf("byte transmission finishes\r\n");
	}

	// address is sent in master mode or received and matches in slave mode interrupt flag
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND))
	{
		i2c0_data.status |= (1 << 12);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND);
		printf("address is sent in master mode or received and matches in slave mode interrupt flag\r\n");
	}

	// start condition sent out in master mode interrupt flag
	if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SBSEND))
	{
		i2c0_data.status |= (1 << 13);
		i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_SBSEND);
		printf("start condition sent out in master mode interrupt flag\r\n");
	}
}

void I2C1_EventIRQ_Handler(void)
{
	if (i2c1_data.master == I2C_MASTER_CH)
	{
		if (i2c1_data.send == 1)
		{
			if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SBSEND))
			{
				/* send slave address */
				i2c_master_addressing(I2C1, i2c1_data.addr, I2C_TRANSMITTER);
			}
			else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND))
			{
				/*clear ADDSEND bit */
				i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);
			}
			else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE))
			{
				if (i2c1_data.txcount > 0)
				{
					/* the master sends a data byte */
					i2c_data_transmit(I2C1, i2c1_data.txbuf[i2c1_data.txindex++]);
					i2c1_data.txcount--;
				}
				else
				{
					/* the master sends a stop condition to I2C bus */
					i2c_stop_on_bus(I2C1);
					i2c1_data.txdone = 1;
					// printf("i2c1 master tx done.\n");
				}
			}
		}
		else // i2c1_data.send == 0
		{
			if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SBSEND))
			{
				/* the master sends slave address */
				i2c_master_addressing(I2C1, i2c1_data.addr, I2C_RECEIVER);
			}
			else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND))
			{
				if ((1 == i2c1_data.rxcount) || (2 == i2c1_data.rxcount))
				{
					/* clear the ACKEN before the ADDSEND is cleared */
					i2c_ack_config(I2C1, I2C_ACK_DISABLE);
					/* clear the ADDSEND bit */
					i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);
				}
				else
				{
					/* clear the ADDSEND bit */
					i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);
				}
			}
			else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE))
			{
				if (i2c1_data.rxcount > 0)
				{
					if (3 == i2c1_data.rxcount)
					{
						/* wait until the second last data byte is received into the shift register */
						while (!i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_BTC))
							;
						/* send a NACK for the last data byte */
						i2c_ack_config(I2C1, I2C_ACK_DISABLE);
					}
					/* read a data byte from I2C_DATA*/
					i2c1_data.rxbuf[i2c1_data.rxindex++] = i2c_data_receive(I2C1);
					i2c1_data.rxcount--;
					if (0 == i2c1_data.rxcount)
					{
						i2c_stop_on_bus(I2C1);
						i2c1_data.rxdone = 1;
						// printf("i2c1 master rx done.\n");

						i2c_ack_config(I2C1, I2C_ACK_ENABLE);
						i2c_ackpos_config(I2C1, I2C_ACKPOS_CURRENT);
						i2c_interrupt_disable(I2C1, I2C_INT_ERR);
						i2c_interrupt_disable(I2C1, I2C_INT_EV);
						i2c_interrupt_disable(I2C1, I2C_INT_BUF);
					}
				}
			} // i2c_interrupt_flag_get
		}
	}
	else // i2c1_data.master == 0
	{
		// recv

		if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND))
		{
			/* clear the ADDSEND bit */
			i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);
		}
		else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE))
		{
			/* if reception data register is not empty ,I2C1 will read a data from I2C_DATA */
			i2c1_data.rxbuf[i2c1_data.rxindex++] = i2c_data_receive(I2C1);
			printf("Received data: %02X\n", i2c1_data.rxbuf[i2c1_data.rxindex]);
		}
		else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_STPDET))
		{
			// printf("I2C1_INT_FLAG_STPDET.\n");

			if (i2c1_data.send == 0)
			{
				i2c1_data.rxdone = 1;

				if(i2c1_data.rxcount <32){
					int result = rt_mq_send(i2c1_mq , (void *)i2c1_data.rxbuf , 128);
					if(result != RT_EOK)
					{
						if(result == -RT_EFULL)
						{
							rt_kprintf("I2C1_EventIRQ_Handler rt_mq_send ERR, rt_mq is Full! err_code = %d\n", result);
						}else{
							rt_kprintf("I2C0_EventIRQ_Handler rt_mq_send ERR, err_code = %d\n", result);
						}
					}
				}else{
					rt_kprintf("i2c1 slave rx data >32 bytes.\n");
				}
				i2c1_data.rxcount = 0;
//				rt_kprintf("i2c1 slave rx done.\n");
				//memset((void *)i2c0_data.rxbuf, 0, 128);
				i2c1_data.rxindex = 0;
			}

			/* clear the STPDET bit */
			i2c_enable(I2C1);
		}

		// send

		if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND))
		{
			/* clear the ADDSEND bit */
			i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);
		}
		else if ((i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE)) && (!i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_AERR)))
		{
			/* send a data byte */
			i2c_data_transmit(I2C1, i2c1_data.txbuf[i2c1_data.txindex++]);

			if (i2c1_data.txcount == i2c1_data.txindex)
			{
				i2c1_data.txdone = 1;
				// i2c1_data.txindex = 0;
				// printf("i2c1 slave tx done.\n");
			}
		}
	}
}

/*!
	\brief      handle I2C1 error interrupt request
	\param[in]  none
	\param[out] none
	\retval     none
*/
void I2C1_ErrorIRQ_Handler(void)
{
	/* no acknowledge received */
	if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_AERR))
	{
		i2c1_data.status |= (1 << 0);
		i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_AERR);
	}

	/* SMBus alert */
	if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SMBALT))
	{
		i2c1_data.status |= (1 << 1);
		i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_SMBALT);
	}

	/* bus timeout in SMBus mode */
	if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SMBTO))
	{
		i2c1_data.status |= (1 << 2);
		i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_SMBTO);
	}

	/* over-run or under-run when SCL stretch is disabled */
	if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_OUERR))
	{
		i2c1_data.status |= (1 << 3);
		i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_OUERR);
	}

	/* arbitration lost */
	if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_LOSTARB))
	{
		i2c1_data.status |= (1 << 4);
		i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_LOSTARB);
	}

	/* bus error */
	if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_BERR))
	{
		i2c1_data.status |= (1 << 5);
		i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_BERR);
	}

	/* CRC value doesn't match */
	if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_PECERR))
	{
		i2c1_data.status |= (1 << 6);
		i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_PECERR);
	}

	/* disable the error interrupt */
	//    i2c_interrupt_disable(I2C1, I2C_INT_ERR);
	//    i2c_interrupt_disable(I2C1, I2C_INT_BUF);
	//    i2c_interrupt_disable(I2C1, I2C_INT_EV);
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_reset_rx_data

** DESCRIPTION	: reset i2cx interrupt receive data

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_reset_rx_data(uint32_t i2c_periph)
{
	I2CX_INTERRUPT_DATA *pdata;

	if (i2c_periph == I2C1)
	{
		pdata = &i2c1_data;
	}
	else if (i2c_periph == I2C0)
	{
		pdata = &i2c0_data;
	}
	else
	{
		printf("i2c_periph not support. I2Cx(x=0,1,2).\n");
		return -1;
	}

	pdata->rxcount = 128;
	pdata->rxindex = 0;
	pdata->rxdone = 0;
	pdata->status = 0;

	return 0;
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_reset_tx_data

** DESCRIPTION	: reset i2cx interrupt transmit data

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_reset_tx_data(uint32_t i2c_periph)
{
	I2CX_INTERRUPT_DATA *pdata;

	if (i2c_periph == I2C1)
	{
		pdata = &i2c1_data;
	}
	else if (i2c_periph == I2C0)
	{
		pdata = &i2c0_data;
	}
	else
	{
		printf("i2c_periph not support. I2Cx(x=0,1,2).\n");
		return -1;
	}

	pdata->txcount = 0;
	pdata->txindex = 0;
	pdata->txdone = 0;
	pdata->status = 0;

	return 0;
}

int i2c_init_data(uint32_t i2c_periph, uint8_t master, uint8_t slave_addr)
{
	/* enable the I2Cx interrupt */
	i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
	i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
	i2c_interrupt_enable(i2c_periph, I2C_INT_EV);

	if (i2c_periph == I2C0)
	{
		memset((void *)&i2c0_data, 0, sizeof(I2CX_INTERRUPT_DATA));
		i2c0_data.master = master;
		i2c0_data.addr = slave_addr;
		i2c0_data.send = 0;
	}
	else if (i2c_periph == I2C1)
	{
		memset((void *)&i2c1_data, 0, sizeof(I2CX_INTERRUPT_DATA));
		i2c1_data.master = master;
		i2c1_data.addr = slave_addr;
		i2c1_data.send = 0;
	}
	else
	{
		printf("invalid i2c_periph=%08x\n", i2c_periph);
		return -1;
	}

	return 0;
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_init

** DESCRIPTION	: initialize i2c hardware and interrupt data

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**                master - 1 master mode
**						   0 slave mode
**                slave_addr - i2cx slace address

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_init(uint32_t i2c_periph, uint8_t master, uint8_t slave_addr)
{
	if (i2c_periph == I2C0)
	{
		memset((void *)&i2c0_data, 0, sizeof(I2CX_INTERRUPT_DATA));
	
		if(i2c0_mutex == RT_NULL)
		{
			i2c0_mutex = rt_mutex_create("i2c0m", RT_IPC_FLAG_FIFO);
			if(i2c0_mutex == RT_NULL)
			{
				rt_kprintf(" create i2c0_mutex failed .\n");
				return -1;
			}
		}

		i2c0_data.master = master;
		i2c0_data.addr = slave_addr;
		i2c0_data.send = 0;

		i2c_deinit(i2c_periph);

		/* enable GPIOB clock */
		rcu_periph_clock_enable(RCU_GPIOB);
		/* enable I2C clock */
		rcu_periph_clock_enable(RCU_I2C0);

		/* connect PB6 to I2C0_SCL, PB7 to I2C0_SDA */
		gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);

		/* configure I2C clock */
		i2c_clock_config(i2c_periph, 100000, I2C_DTCY_2);
		/* I2C address configure */
		i2c_mode_addr_config(i2c_periph, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, slave_addr);
		/* enable I2C0 */
		i2c_enable(i2c_periph);
		/* enable acknowledge */
		i2c_ack_config(i2c_periph, I2C_ACK_ENABLE);

		nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);

		nvic_irq_enable(I2C0_EV_IRQn, 0, 3);
		nvic_irq_enable(I2C0_ER_IRQn, 0, 2);
	}
	else if (i2c_periph == I2C1)
	{
		memset((void *)&i2c1_data, 0, sizeof(I2CX_INTERRUPT_DATA));
	
		if(i2c1_mutex == RT_NULL)
		{
			i2c1_mutex = rt_mutex_create("i2c1m", RT_IPC_FLAG_FIFO);
			if(i2c1_mutex == RT_NULL)
			{
				rt_kprintf(" create i2c1_mutex failed .\n");
				return -1;
			}
		}

		i2c1_data.master = master;
		i2c1_data.addr = slave_addr;
		i2c1_data.send = 0;

		i2c_deinit(i2c_periph);

		nvic_irq_enable(I2C1_EV_IRQn, 0, 4);
		nvic_irq_enable(I2C1_ER_IRQn, 0, 1);

		/* enable GPIOB clock */
		rcu_periph_clock_enable(RCU_AF);
		rcu_periph_clock_enable(RCU_GPIOB);
		/* connect PB10 to I2C1_SCL, PB11 to I2C2_SDA */
		gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_11);
		/* connect PB12 to I2C1_SMBA*/
		//		gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_12);

		/* enable I2C clock */
		rcu_periph_clock_enable(RCU_I2C1);
		/* configure I2C clock */
		i2c_clock_config(i2c_periph, 100000, I2C_DTCY_2);
		/* I2C address configure */
		i2c_mode_addr_config(i2c_periph, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, slave_addr);
		/* enable I2C1 */
		i2c_enable(i2c_periph);
		/* enable acknowledge */
		i2c_ack_config(i2c_periph, I2C_ACK_ENABLE);

		//		IPMB_B_EN_HIGH;
	}
	else
	{
		printf("invalid i2c_periph=%08x\n", i2c_periph);
		return -1;
	}

	return 0;
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_master_send

** DESCRIPTION	: send data in master transmit mode

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**                slave_addr - i2cx slace address
**                buf - data to transmit
**                len - data length to transmit

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_master_send(uint32_t i2c_periph, uint8_t slave_addr, uint8_t *buf, uint32_t len)
{
	I2CX_INTERRUPT_DATA *pdata;
	int timeout = 100000;
	rt_mutex_t mutex;

	if (i2c_periph == I2C0)
	{
		pdata = &i2c0_data;
		mutex = i2c0_mutex;
	}
	else if (i2c_periph == I2C1)
	{
		pdata = &i2c1_data;
		mutex = i2c1_mutex;
	}
	else
	{
		rt_kprintf("i2c_periph not support. I2Cx(x=0,1,2).\n");
		return -1;
	}
	
	if(rt_mutex_take(mutex , RT_WAITING_FOREVER) != RT_EOK)
	{
		rt_kprintf("i2c_master_send() rt_mutex_take return error.\n");
		return -1;
	}

	i2c_reset_tx_data(i2c_periph);

	pdata->addr = slave_addr;
	pdata->master = I2C_MASTER_CH;
	pdata->send = 1;
	memcpy((void *)&pdata->txbuf[0], buf, len);
	pdata->txcount = len;

	/* enable the I2Cx interrupt */
	i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
	i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
	i2c_interrupt_enable(i2c_periph, I2C_INT_EV);

	/* the master waits until the I2C bus is idle */
	timeout = 200;
	while (i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) && (timeout--))
	{
		if (i2c0_data.status != 0)
		{
			printf("Line%d: Release I2C bus\r\n", __LINE__);
			i2c0_data.status = 0;
			i2c_init(I2C0, I2C_SLAVE_CH, I2C0_SLAVE_ADDRESS); // 初�?�化释放总线
		}
		rt_thread_mdelay(1);
	}

	if (timeout <= 0)
	{
		rt_kprintf("i2c_master_send() timeout waits until the I2C bus is idle\n");

		i2c_stop_on_bus(i2c_periph);
		rt_thread_mdelay(20);
		if (i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY))
		{
			printf("Reinit I2C%d\n", (i2c_periph == I2C1) ? 1 : 0);

			i2c_deinit(i2c_periph);

			/* configure I2C clock */
			i2c_clock_config(i2c_periph, 100000, I2C_DTCY_2);
			/* I2C address configure */
			i2c_mode_addr_config(i2c_periph, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, slave_addr);
			/* enable I2C0 */
			i2c_enable(i2c_periph);
			/* enable acknowledge */
			i2c_ack_config(i2c_periph, I2C_ACK_ENABLE);
		}

		/* disable the error interrupt */
		i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
		i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);

		return -1;
	}

	/* the master sends a start condition to I2C bus */
	i2c_start_on_bus(i2c_periph);

	timeout = 200000;
	while ((pdata->txdone == 0) && (pdata->status == 0) && (timeout--))
	{
		if (i2c0_data.status != 0)
		{
			printf("Line%d: Release I2C bus\r\n", __LINE__);
			i2c0_data.status = 0;
			i2c_init(I2C0, I2C_SLAVE_CH, I2C0_SLAVE_ADDRESS); // 初�?�化释放总线
		}
	}

	if (timeout <= 0)
	{
		printf("i2c_master_send() timeout waits until the I2C bus is send\n");

		i2c_stop_on_bus(i2c_periph);
		/* disable the error interrupt */
		i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
		i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);

		return -1;
	}

	if (pdata->status != 0)
	{
		printf("i2c_master_send() error status=%08X\n", pdata->status);
		i2c_stop_on_bus(i2c_periph);
		/* disable the error interrupt */
		i2c_interrupt_disable(i2c_periph, I2C_INT_ERR);
		i2c_interrupt_disable(i2c_periph, I2C_INT_EV);
		i2c_interrupt_disable(i2c_periph, I2C_INT_BUF);
		
		rt_mutex_release(mutex);
		return -1;
	}
	
	rt_mutex_release(mutex);
	return 0;
}

/*-----------------------------------------------------------------------------
** PROC NAME	: i2c_slave_recv

** DESCRIPTION	: receive data in slave receive mode

** PARAMETERS	: i2c_periph - I2Cx(x=0,1,2)
**                slave_addr - i2cx slace address
**                buf - data to receive
**                len - data length to receive

** RETURN       : 0 - success, -1 - fail.

** NOTES:
**----------------------------------------------------------------------------*/
int i2c_slave_recv(uint32_t i2c_periph, uint8_t slave_addr, uint8_t *buf, uint32_t *len)
{
	I2CX_INTERRUPT_DATA *pdata;
	//	int timeout = 100000;

	if (i2c_periph == I2C0)
	{
		pdata = &i2c0_data;
	}
	else if (i2c_periph == I2C1)
	{
		pdata = &i2c1_data;
	}
	else
	{
		printf("i2c_periph not support. I2Cx(x=0,1,2).\n");
		return -1;
	}

	i2c_reset_rx_data(i2c_periph);

	//	pdata->addr = slave_addr;
	pdata->master = I2C_MASTER_CH;
	pdata->send = 0;
	pdata->rxcount = 128;

	/* enable the I2Cx interrupt */
	i2c_interrupt_enable(i2c_periph, I2C_INT_ERR);
	i2c_interrupt_enable(i2c_periph, I2C_INT_BUF);
	i2c_interrupt_enable(i2c_periph, I2C_INT_EV);

	while ((pdata->rxdone == 0) && (pdata->status == 0))
		;

	if (pdata->status != 0)
	{
		printf("i2c_slave_recv() error status=%08X\n", pdata->status);
		return -1;
	}

	*len = pdata->rxindex;
	memcpy(buf, (void *)&pdata->rxbuf[0], *len);

	return 0;
}

/*!
	\brief      this function handles I2C0 event interrupt request exception
	\param[in]  none
	\param[out] none
	\retval     none
*/
void I2C0_EV_IRQHandler(void)
{
	I2C0_EventIRQ_Handler();
}

/*!
	\brief      this function handles I2C0 error interrupt request exception
	\param[in]  none
	\param[out] none
	\retval     none
*/
void I2C0_ER_IRQHandler(void)
{
	I2C0_ErrorIRQ_Handler();
}

/*!
	\brief      this function handles I2C1 event interrupt request exception
	\param[in]  none
	\param[out] none
	\retval     none
*/
void I2C1_EV_IRQHandler(void)
{
	I2C1_EventIRQ_Handler();
}

/*!
	\brief      this function handles I2C1 error interrupt request exception
	\param[in]  none
	\param[out] none
	\retval     none
*/
void I2C1_ER_IRQHandler(void)
{
	I2C1_ErrorIRQ_Handler();
}
